package org.smile.upload;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.smile.json.JSONObject;
import org.smile.servlet.BaseServlet;
import org.smile.upload.http.DefaultUploadReportManage;
import org.smile.upload.http.ServletFileUpload;
import org.smile.upload.http.UploadReport;
import org.smile.util.RegExp;
import org.smile.util.UUIDGenerator;
/**
 * 上传附件servlet
 * @author strive
 *
 */
public class FileUploadServlet extends BaseServlet {

	private String uploadDir;
	/**
	 * 允许上传的格式
	 */
	private String allowTypes;
	/**
	 * 上传文件大小限制
	 */
	private long limitSize;
	/**
	 * 单个文件大小限制
	 */
	private long singleLimitSize;
	
	private FileUploadHandler handler;
	
	@Override
	public void execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		DiskFileItemFactory factory = new DiskFileItemFactory();
		   factory.setSizeThreshold(1024*1024);
		   if(uploadDir!=null){
			   File fileFoder=new File(uploadDir);
				if(!fileFoder.exists())
				{
					fileFoder.mkdir();
				}
			   factory.setRepository(fileFoder);
		   }
		   ServletFileUpload upload = new ServletFileUpload(factory);

		   upload.addAllowFileTypes(allowTypes);
		   upload.setFileLimitSize(singleLimitSize*1024);
		   //设置总共最大文件
		   if(limitSize!=0){
			   upload.setSizeMax(limitSize*1024);
		   }
		   //保存所有表单参数内容
	       UploadFormParameter parameter=new UploadFormParameter();
		   try
		   {
		       List fileItemList = upload.parseRequest(request);
				//保存文件参数内容 
				int i=0,size=fileItemList.size();
				for (i=0;i<size;i++)
				{
					FileItem item=(FileItem)fileItemList.get(i);
					//如果是表单数据则把表单数据封装到一个map中
					if (item.isFormField())
					{
						String fieldName=item.getFieldName();
						parameter.addValue(fieldName,item.getString(encode));
					}
					//处理文件类型
					else if (!item.isFormField())
					{
						//表单的字段名
						String fieldName = item.getFieldName();
						String value = item.getName();
						//如果名字不为空
						if(null!=value&&!"".equals(value.trim()))
						{
							int start = value.lastIndexOf("\\");
							//文件名
							String fileName = value.substring(start + 1);
							
							String[] strs=new RegExp("[.]+").split(fileName);
							String extendsName="dat";
							if(strs!=null)
							{
								extendsName=strs[strs.length-1];
							}
							String newId=UUIDGenerator.createUUid();
							//新文件名
							String newFileName=newId+"."+extendsName;
							//文件类型
							String fileContentType=item.getContentType();
							//写文件到硬盘目录中
							item.write(new File(uploadDir,newFileName));
							
							FileInfo info=new FileInfo();
							info.setId(newId);
							info.setOldFileName(fileName);
							//数据库中保存的是新的文件名
							info.setNewFileName(newFileName);
							info.setFileContentType(fileContentType);
							info.setExtName(extendsName);
							
							parameter.addValue(fieldName, info);
							
						}else{
							parameter.addValue(fieldName, new FileInfo());
						}
					}
				}
		   }catch(FileUploadException e){
			   logger.error("上传文件出错：",e);
			   PrintWriter pw=response.getWriter();
			   Map error=new HashMap(1);
			   error.put("error", e.getMessage());
			   pw.print(JSONObject.toJSONString(error));
			   return;
		   }finally
		   {
		       upload.dispose();
		   }
		   if(handler!=null){
			   handler.afterUpload(request, response, parameter);
		   }
		   PrintWriter pw=response.getWriter();
		   FileInfo info=parameter.getFirstInfo();
		   pw.print(JSONObject.toJSONString(info));
	}
	
	public void getDetail(HttpServletRequest request, HttpServletResponse response) throws ServletException{
		HttpSession ses=request.getSession(false);
		UploadReport reportItem=DefaultUploadReportManage.getItem(ses);
		PrintWriter pw;
		try {
			pw = response.getWriter();
			if (reportItem!=null){
				String info=reportItem.getCompletePercent()+"||"
				+reportItem.getFileName()+"||"
				+reportItem.getUploadSpeedKB()+"||"
				+reportItem.getUploadSizeMKB()+"||"
				+reportItem.getTotalSizeMKB()+"||"
				+reportItem.getRemainTimeHMS()+"||"
				+reportItem.getTotalTimeHMS(); 
				pw.println(info);
			}
		} catch (IOException e) {
			throw new ServletException(e);
		}
	}
	/**
	 * 得到上传文件信息及上传进度信息
	 * @param request
	 * @param response
	 * @throws ServletException
	 */
	public void getUloadInfo(HttpServletRequest request, HttpServletResponse response) throws ServletException{
		HttpSession ses=request.getSession(false);
		UploadReport reportItem=DefaultUploadReportManage.getItem(ses);
		PrintWriter pw;
		try {
			pw = response.getWriter();
			if (reportItem!=null){
				Map info=new HashMap();
				info.put("info", reportItem.getFileName());
				info.put("speed", reportItem.getUploadSpeedKB());
				info.put("uploaded", reportItem.getUploadSizeMKB());
				info.put("totals", reportItem.getTotalSizeMKB());
				info.put("remainTime", reportItem.getRemainTimeHMS());
				info.put("totalTime", reportItem.getTotalTimeHMS());
				info.put("percent", reportItem.getCompletePercent());
				pw.println(JSONObject.toJSONString(info));
			}
		} catch (IOException e) {
			throw new ServletException(e);
		}
	}
	/**
	 * 得到上传文件信息及上传进度信息
	 * @param request
	 * @param response
	 * @throws ServletException
	 */
	public void download(HttpServletRequest request, HttpServletResponse response) throws ServletException{
		File file;
		String oldFileName;
		String fileType;
		if(this.handler!=null){
			FileInfo info=handler.downloadInfo(request, response);
			file=new File(this.uploadDir,info.getNewFileName());
			oldFileName=info.getOldFileName();
			fileType=info.getFileContentType();
		}else{
			String filename=request.getParameter("filename");
			file=new File(this.uploadDir,filename);
			fileType="application/unkonw;"+encode;
			oldFileName=filename;
		}
		BufferedInputStream bi = null;
		OutputStream os = null;
		InputStream is = null;
		try {
			if (!file.exists()) {
				PrintWriter writer = response.getWriter();
				writer.print("<script>alert('文件不存在');</script>");
			} else {
				if (fileType != null) {
					response.setContentType(fileType+";"+encode);
				} else {
					response.setContentType("application/download;"+encode);
				}
				response.setHeader("Content-disposition","attachment; filename=\"" + java.net.URLEncoder.encode(oldFileName,encode) + "\"");
				bi = new BufferedInputStream(new FileInputStream(file));
				os = response.getOutputStream();
				byte[] buffer = new byte[1024];
				int count = 0;
				while ((count = bi.read(buffer)) != -1) {
					os.write(buffer, 0, count);
				}
				os.flush();
			}
		} catch (Exception e) {
			logger.error("下载文件出错：" + e);
		} finally {
			if (bi != null) {
				try {
					bi.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (os != null) {
				try {
					os.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	/**
	 * 得到上传文件信息及上传进度信息
	 * @param request
	 * @param response
	 * @throws ServletException
	 */
	public void deleteFile(HttpServletRequest request, HttpServletResponse response) throws ServletException{
		File file;
		if(this.handler!=null){
			FileInfo info=handler.downloadInfo(request, response);
			if(info!=null){
				file=new File(this.uploadDir,info.getNewFileName());
				file.delete();
			}
		}else{
			String filename=request.getParameter("filename");
			file=new File(this.uploadDir,filename);
			file.delete();
		}
		try {
			response.getWriter().println("删除文件成功");
		} catch (IOException e) {
			throw new ServletException("删除文件出错",e);
		}
	}
	@Override
	public void init() throws ServletException {
		super.init();
		String handlerClass=this.getInitParameter("handlerClass");
		if(handlerClass!=null){
			try {
				handler=(FileUploadHandler)Class.forName(handlerClass).newInstance();
			} catch (Exception e) {
				logger.error("FileUploadHandler 实例化失败",e);
			}
		}
		this.uploadDir=this.getInitParameter("uploadDir");
		if(this.getInitParameter("limitSize")!=null){
			this.limitSize=Long.parseLong(this.getInitParameter("limitSize"));
		}
		if(this.getInitParameter("singleLimitSize")!=null){
			this.singleLimitSize=Long.parseLong(this.getInitParameter("singleLimitSize"));
		}
	}
	
}
